<?php

namespace Hilaoyu\ComputeCloudClient\ctyun;

use Fernet\Fernet;
use Hilaoyu\Utils\Traits\ErrorsTrait;
use Hilaoyu\Utils\UtilArr;
use Hilaoyu\Utils\UtilHttp;
use Hilaoyu\Utils\UtilStr;

/**
 *
 */

abstract class CtyunClient
{
    use ErrorsTrait;

    protected $accessKeyId;
    protected $accessKeySecret;
    /**
     * @var string
     */
    protected $projectId;
    protected $regionId;
    /**
     * @var UtilHttp
     */
    protected $httpClient;

    protected $headers=[];

    /**
     * @var Fernet
     */
    protected $fernet;



    static public function make($accessKeyId, $accessKeySecret,string $projectId="",$regionId=null){
        return new static($accessKeyId, $accessKeySecret,$projectId,$regionId);
    }

    public function __construct($accessKeyId, $accessKeySecret,string $projectId="",$regionId=null){
        $this->accessKeyId = $accessKeyId;
        $this->accessKeySecret = $accessKeySecret;
        $this->projectId = $projectId;
        $this->regionId = $regionId;
        $this->fernet = new Fernet(base64_encode("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"));
    }

    protected function getRegionId($regionId=''){
        $regionId = trim($regionId);
        if(!$regionId){
            $regionId = $this->regionId;
        }
        return $regionId;
    }

    public function setHeaders($headers)
    {
        $this->headers = (array)$headers;
    }

    abstract protected function baseUrl():string;

    protected function buildClient(){
        if(!$this->httpClient){
            $this->httpClient = new UtilHttp($this->baseUrl());
        }
        return $this->httpClient;
    }

    public function comCreateGuid()
    {

        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',

            mt_rand(0, 0xffff), mt_rand(0, 0xffff),

            mt_rand(0, 0xffff),

            mt_rand(0, 0x0fff) | 0x4000,

            mt_rand(0, 0x3fff) | 0x8000,

            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)

        );

    }

    private function en($str, $pass)
    {
        return  hash_hmac('sha256', $str, $pass, true);
    }

    private function buildHeader($query, $body)
    {
        $requestId = $this->comCreateGuid();
        //$requestId = "99416832-6b15-490b-858a-028c2544ef7c";
        $time = date('Ymd', time()) . 'T' . date('His') . 'Z';
        //$time = "20250519T115350Z";
        $timeDate = substr($time, 0, 8);
        $bodyHash = bin2hex(hash("sha256", $body, true));

        $strsignature = "ctyun-eop-request-id:" . $requestId . "\n" . "eop-date:" . $time . "\n" . "\n" . $query . "\n" . $bodyHash;

        $Ktime = $this->en($time, $this->accessKeySecret);

        $kAk = $this->en($this->accessKeyId, $Ktime);

        $kdate = $this->en($timeDate, $kAk);

        $signature = base64_encode(($this->en($strsignature, $kdate)));


        $header = array(
            'ctyun-eop-request-id' => $requestId,
            'Eop-Authorization' => $this->accessKeyId . ' Headers=ctyun-eop-request-id;' . 'eop-date Signature=' . $signature,
            'eop-date' => $time,
        );
        return array_merge_recursive($this->headers,$header);
    }

    protected function request($path,$params = [],$query=[], $method = "post")
    {
        $params = (array)$params;
        if("" != $this->projectId){
            if (in_array($method, ['get', 'delete'])) {
                $query["projectID"] = $this->projectId;
            }else{
                $params["projectID"] = $this->projectId;
            }
        }

        if (in_array($method, ['get', 'delete'])) {
            if(!UtilArr::get($query,"regionID") && $this->regionId){
                $query["regionID"] = $this->regionId;
            }
        }else{
            if(!UtilArr::get($params,"regionID") && $this->regionId){
                $params["regionID"] = $this->regionId;
            }
        }

        $body = "";
        if(!empty($params)){
            $body = json_encode($params);
        }
        $query = (array)$query;
        $queryStr = "";
        $httpClient = $this->buildClient();
        if(!empty($query)){
            $path = $httpClient::buildUrl($path,$query);
        }
        $path_parse = parse_url($path);
        if (array_key_exists('query', $path_parse)) {
            $queryData = explode('&', $path_parse['query']);
            // 排序
            sort($queryData);
            // 拼接query待签名字符串
            $queryStr = implode('&', $queryData);
        }
        $headers = $this->buildHeader($queryStr,$body);
        $headers['Content-Type'] = "application/json";
        $result = $httpClient->httpRequestJson($path,$body,$method,$headers);
        $errors = $httpClient->getError();

        //dump("--request--",$path,$query,$body,$result,$errors,"--request end--");


        if(!$result){
            $this->setError($errors);
            return null;
        }

        $statusCode = UtilArr::get($result,"statusCode");
        if(800 != $statusCode){
            $this->setError("错误[".$statusCode.";".UtilArr::get($result,"errorCode")."]:".UtilArr::get($result,"message") .";".UtilArr::get($result,"error").";".UtilArr::get($result,"description"));
            return null;
        }

        return $result;
    }






}
